/* 
* File:   SpamFilter.h
* Author: Wardell Bagby
*      
*/
#include "Entry.h"
#include "email.h"
#include "SpamEquationsApplication2.h"
namespace Project3
{
	using namespace System;
	using namespace System::IO;
	using namespace System::Collections;
	using namespace System::Collections::Generic;	
	using namespace E;
	using namespace System::Text;
	using namespace System::Windows::Forms;
	public ref class KeyValuePairComparer: Collections::Generic::IComparer<KeyValuePair<String^,double>>
	{
	public:
		virtual int Compare(KeyValuePair<String^,double> x, KeyValuePair<String^,double> y)
		{
			return y.Value.CompareTo(x.Value);
		};
	};
	/**Handles all of the Spam filter calculations and checking to see if an email is spam**/
	ref class SpamFilter
	{
	private:
		List<Entry^>^ spamProb;
		FileStream^ spamFile;
		int numberInSpam;
		double median;
		int numberInHam;
		Email^ email;
		bool isSpam;
	public:
		/**Default constructor.**/
		SpamFilter()
		{
			spamProb = gcnew List<Entry^>();
			median = .5;
			email = gcnew Email();
		};
		/**Sets the spam file and reads it in. Returns if it read successfully or not.**/
		bool setSpamFile(FileStream^ f)
		{
			spamFile = f;
			return readInSpamFile();
		};
		/**Sets the current Email**/
		void setEmail(Email^ e)
		{
			email = e;
		};
		/**Gets the current email.**/
		Email^ getEmail()
		{
			return email;
		};
		/**Gets the current median.**/
		int getMedian()
		{
			return median;
		};
		/**Reads in the email. If the first line is "Spam" or "Ham", ignores it.**/
		void readInEmail(FileStream^ e)
		{
			StreamReader^ sR = gcnew StreamReader(e);
			String^ line;
			String^ delim = " \n";
			int count = 0;
			StringBuilder^ sB = gcnew StringBuilder();
			while((line = sR->ReadLine())!=nullptr)
			{
				if(!line->Equals("Spam") && !line->Equals("Ham"))
				{
				array<String^>^ words = line->Split(delim->ToCharArray());
				count+=words->Length;
				sB->Append(line);
				sB->AppendLine();
				}
			}
			email = gcnew Email(sB->ToString(),count);
			sR->Close();			
			e->Close();
			e = nullptr;
		};
		/**Reads in the SpamFilter file and creates the Entries.**/
		bool readInSpamFile()
		{
			StreamReader^ sR = gcnew StreamReader(spamFile);	
			String^ line;
			String^ delim = ":\n";
			while((line = sR->ReadLine())!=nullptr)
			{
				try
				{
					array<String^>^ words = line->Split(delim->ToCharArray());
					if(words->Length>=7)
					{
						Entry^ e = gcnew Entry(words[0],Convert::ToInt32(words[1]),Convert::ToInt32(words[2]),Convert::ToInt32(words[3]),Convert::ToInt32(words[4]),Convert::ToDouble(words[5]),Convert::ToDouble(words[6]),Convert::ToDouble(words[7]));
						spamProb->Add(e);

					}
				}catch(Exception^ e)
				{
					MessageBox::Show(nullptr,"Error reading in SpamFilter file. Please select a different file.\n\n"+e->StackTrace+"\n\n"+line,"Error: "+e->Message,MessageBoxButtons::OK,MessageBoxIcon::Error);
					return false;
				}
			}
			sR->Close();
			spamFile->Close();
			spamFile = nullptr;
			return true;
		};
		/**Sets the median.**/
		void setMedian(double med)
		{
			median = med;
		};
		/**Gets the SpamFilter file**/
		FileStream^ getSpamFile()
		{
			return spamFile;
		};
		/**Returns the Ham percentage for a word if it's in the SpamFilter's entries. Returns 0 otherwise.**/
		double getHamPercentage(String^ word)
		{ 
			for(int i=0; i<spamProb->Count;i++)
			{
				if(spamProb[i]->GetWord()->ToLower()->Equals(word->ToLower()))
					return spamProb[i]->GetPercentageInHam();
			}
			return 0;

		};
		/**Returns the Spam percentage for a word if it's in the SpamFilter's entries. Returns 0 otherwise.**/
		double getSpamPercentage(String^ word)
		{ 
			for(int i=0; i<spamProb->Count; i++)////
			{
				if(spamProb[i]->GetWord()->ToLower()->Equals(word->ToLower()))
					return spamProb[i]->GetPercentageInSpam();
			}
			return 0;
		};
		/**Calculates the probability that an email is spam. Returns the top words with the percentage that the email is spam tacked on
		to the end. The spam probability percentage doesn't seem to be correct...ever. I'm not sure why; the math looks fine.**/
		array<String^>^ calculateProbablity(Email^ e)
		{
			String^ message = e->getBody();
			List<double>^ spamPercentages = gcnew List<double>;
			List<double>^ hamPercentages = gcnew List<double>;
			array<double>^ topValuePercents = gcnew array<double>(15);
			array<int>^ topValueIndexes = gcnew array<int>(15);
			String^ delims = " :?.!@*,\n\r";
			array<String^>^ words = message->Split(delims->ToCharArray());

			List<KeyValuePair<String^, double>>^ wordHamPercents = gcnew List<KeyValuePair<String^, double>>();
			List<KeyValuePair<String^, double>>^ wordSpamPercents = gcnew List<KeyValuePair<String^, double>>();
			for(int i=0; i<words->Length; i++)
			{
				KeyValuePair<String^,double> kvp1 = KeyValuePair<String^,double>(words[i],getSpamPercentage(words[i]));
				KeyValuePair<String^,double> kvp2 = KeyValuePair<String^,double>(words[i],getHamPercentage(words[i]));
				wordSpamPercents->Add(kvp1);
				wordHamPercents->Add(kvp2);
			}
			KeyValuePairComparer^ compare = gcnew KeyValuePairComparer();
			wordSpamPercents->Sort(compare);
			wordHamPercents->Sort(compare);
			array<String^>^ topWords = gcnew array<String^>(16);
			for(int i=0; i<15; i++)
			{
				if(wordHamPercents[i].Value > wordSpamPercents[i].Value)
				{
					topWords[i] = wordHamPercents[i].Key;
					topValuePercents[i] = wordHamPercents[i].Value;
				}
				else
				{
					topWords[i] = wordSpamPercents[i].Key;
					topValuePercents[i] = wordSpamPercents[i].Value;
				}
			}
			topWords[15] = ""+spamFilterIndicatorValueEquation(topValuePercents,topValuePercents->Length);	
			return topWords;
		};

	};
}